package com.ctg.itrdc.imageconsole.control.deploy;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

import com.ctg.itrdc.imageconsole.common.bean.CommonResult;
import com.ctg.itrdc.imageconsole.common.bean.ReturnCodeDefine;
import com.ctg.itrdc.imageconsole.common.util.PropertiesUtils;
import com.ctg.itrdc.imageconsole.common.util.TimeUtils;
import com.ctg.itrdc.imageconsole.data.dto.DmsAppDTO;
import com.ctg.itrdc.imageconsole.data.dto.DmsAppReturnDTO;
import com.ctg.itrdc.imageconsole.data.dto.DmsAppServiceDTO;
import com.ctg.itrdc.imageconsole.data.dto.DmsAppServicesDTO;
import com.ctg.itrdc.imageconsole.data.dto.DmsFixedJsonDTO;
import com.ctg.itrdc.imageconsole.data.dto.DmsRollbackDTO;
import com.ctg.itrdc.imageconsole.data.dto.DmsServiceDTO;
import com.ctg.itrdc.imageconsole.data.dto.DmsServiceReturnDTO;
import com.ctg.itrdc.imageconsole.service.deploy.AppManagerService;
import com.ctg.itrdc.imageconsole.service.deploy.AppManagerServiceAux;
import com.ctg.itrdc.imageconsole.service.deploy.GroupManager;
import com.ctg.itrdc.pasp.security.utils.WebUtils;
import com.ctg.itrdc.paspsdk.common.entity.PageInfo;

@Controller
@RequestMapping("/dms")
public class AppManagerController {

	private static Logger logger = LoggerFactory.getLogger(AppManagerController.class);

	@Resource
	private AppManagerService appManagerService;

	@Resource
	private AppManagerServiceAux appManagerServiceAux;

	@Resource
	private GroupManager groupManager;

	@RequestMapping(value = "/fixedJson", method = RequestMethod.POST)
	@ResponseBody
	public CommonResult getFixedJson(@RequestBody DmsFixedJsonDTO fixedJson) {
		try {
			if (null == fixedJson)
				throw new RuntimeException("Error : parameter fixedJson is null");
			if (null == fixedJson.getServiceCode() || null == fixedJson.getReplicas())
				throw new RuntimeException("Error : some parameters are null, check them");
			if (null != fixedJson.getCpuLimit() && "".equals(fixedJson.getCpuLimit()))
				fixedJson.setCpuLimit(null);
			if (null != fixedJson.getMemoryLimit() && "".equals(fixedJson.getMemoryLimit()))
				fixedJson.setMemoryLimit(null);
			Object rc = appManagerService.newFixedJson(fixedJson);
			return new CommonResult(ReturnCodeDefine.Code.C1000, ReturnCodeDefine.Msg.M1000, rc);
		} catch (Exception e) {
			logger.error(e.getMessage());
			return new CommonResult(ReturnCodeDefine.Code.C1200, e.getMessage(), null);
		}
	}

	@RequestMapping(value = "/fixedJsonList", method = RequestMethod.POST)
	@ResponseBody
	public CommonResult getFixedJsonList(@RequestBody List<DmsFixedJsonDTO> fixedJsonList) {
		try {
			if (null == fixedJsonList)
				throw new RuntimeException("Error : parameter fixedJsonList is null");
			// 判断设置的cpu和memory是否超过当前租户剩下的
			String resultMsg = appManagerService.checkCpuAndMemory(fixedJsonList);
			if (null != resultMsg) {
				return new CommonResult(ReturnCodeDefine.Code.C1200, resultMsg, null);
			}
			List<Object> rcList = new ArrayList<>();
			for (DmsFixedJsonDTO fixedJson : fixedJsonList) {
				if (null == fixedJson.getServiceCode() || null == fixedJson.getReplicas())
					throw new RuntimeException("Error : some parameters are null, check them");
				if (null != fixedJson.getCpuLimit() && "".equals(fixedJson.getCpuLimit()))
					fixedJson.setCpuLimit(null);
				if (null != fixedJson.getMemoryLimit() && "".equals(fixedJson.getMemoryLimit()))
					fixedJson.setMemoryLimit(null);
				Object rc = appManagerService.newFixedJson(fixedJson);
				rcList.add(rc);
			}
			return new CommonResult(ReturnCodeDefine.Code.C1000, ReturnCodeDefine.Msg.M1000, rcList);
		} catch (Exception e) {
			logger.error(e.getMessage());
			return new CommonResult(ReturnCodeDefine.Code.C1200, e.getMessage(), null);
		}
	}

	@RequestMapping(value = "/app/create", method = RequestMethod.POST)
	@ResponseBody
	public CommonResult createApp(@RequestBody DmsAppServicesDTO appServices) {
		try {
			// check app (appCode, appName)
			DmsAppDTO app = appServices.getApp();
			if (null == app || null == app.getAppCode() || null == app.getAppName())
				throw new RuntimeException("Error : some parameter is null");

			// check if services.size() == autoscalePolicies.size()
			List<DmsServiceDTO> services = appServices.getServices();
			if (null == services)
				throw new RuntimeException("Error : some parameter is null");

			// check service (serviceCode, isAutoscalable, yamlContent, k8sCode)
			for (DmsServiceDTO service : services) {
				if (null == service || null == service.getServiceCode() || null == service.getIsAutoscalable()
						|| null == service.getYamlContent() || null == service.getK8sCode())
					throw new RuntimeException("Error : some parameter is null");
				if (1 == service.getIsAutoscalable())
					checkAutoscalePolicy(service);
			}

			if (appManagerService.appCodeExist(WebUtils.getCtgUser().getSysUserId(), app.getNamespace(), app.getAppCode()))
				return new CommonResult(ReturnCodeDefine.Code.C1105, "Invalid appCode", null);
			Long appId = appManagerService.createApp(appServices);
			return new CommonResult(ReturnCodeDefine.Code.C1000, ReturnCodeDefine.Msg.M1000, appId);
		} catch (Exception e) {
			logger.error(e.getMessage());
			return new CommonResult(ReturnCodeDefine.Code.C1200, e.getMessage(), null);
		}
	}

	@RequestMapping(value = "/app/delete", method = RequestMethod.POST)
	@ResponseBody
	public CommonResult deleteApp(@RequestBody DmsAppDTO appDTO) {
		try {
			if (null == appDTO.getAppId())
				throw new RuntimeException("Error : some parameter is null");
			appManagerService.deleteApp(appDTO.getAppId());
			return new CommonResult(ReturnCodeDefine.Code.C1000, ReturnCodeDefine.Msg.M1000, "Task committed");
		} catch (Exception e) {
			logger.error(e.getMessage());
			return new CommonResult(ReturnCodeDefine.Code.C1200, e.getMessage(), null);
		}
	}

	@RequestMapping(value = "/app/updateDescription", method = RequestMethod.POST)
	@ResponseBody
	public CommonResult updateAppDescription(@RequestBody DmsAppDTO app) {
		try {
			if (null == app.getAppId())
				throw new RuntimeException("Error : some parameters are null, check them");
			appManagerServiceAux.updateAppDescription(app);
			return new CommonResult(ReturnCodeDefine.Code.C1000, ReturnCodeDefine.Msg.M1000,
					"update app content success");
		} catch (Exception e) {
			logger.error(e.getMessage());
			return new CommonResult(ReturnCodeDefine.Code.C1200, e.getMessage(), null);
		}
	}

	@RequestMapping(value = "/app/service/terminate", method = RequestMethod.POST)
	@ResponseBody
	public CommonResult terminateService(@RequestBody DmsServiceDTO service) {
		try {
			if (null == service || null == service.getServiceId())
				throw new RuntimeException("Error : some parameters are null, check them");
			appManagerService.terminateService(service.getServiceId());
			return new CommonResult(ReturnCodeDefine.Code.C1000, ReturnCodeDefine.Msg.M1000, "terminating success");
		} catch (Exception e) {
			logger.error(e.getMessage());
			return new CommonResult(ReturnCodeDefine.Code.C1200, e.getMessage(), null);
		}
	}

	@RequestMapping(value = "/app/service/create", method = RequestMethod.POST)
	@ResponseBody
	public CommonResult createService(@RequestBody DmsAppServiceDTO appService) {
		try {
			// check app (appId)
			DmsAppDTO app = appService.getApp();
			if (null == app || null == app.getAppId())
				throw new RuntimeException("Error : parameter appId is null, check them");

			// check service (serviceCode, k8sCode, isAutoscalable)
			DmsServiceDTO service = appService.getService();
			if (null == service || null == service.getServiceCode() || null == service.getIsAutoscalable()
					|| null == service.getYamlContent() || null == service.getK8sCode())
				throw new RuntimeException("Error : some parameter is null");

			if (1 == service.getIsAutoscalable().intValue())
				checkAutoscalePolicy(service);

			Long serviceId = appManagerService.createService(app, service);
			return new CommonResult(ReturnCodeDefine.Code.C1000, ReturnCodeDefine.Msg.M1000, serviceId);
		} catch (Exception e) {
			logger.error(e.getMessage());
			return new CommonResult(ReturnCodeDefine.Code.C1200, e.getMessage(), null);
		}
	}

	@RequestMapping(value = "/app/service/delete", method = RequestMethod.POST)
	@ResponseBody
	public CommonResult deleteService(@RequestBody DmsServiceDTO service) {
		try {
			if (null == service.getServiceId())
				throw new RuntimeException("Error : some parameters are null, check them");
			appManagerService.deleteService(service.getServiceId());
			;
			return new CommonResult(ReturnCodeDefine.Code.C1000, ReturnCodeDefine.Msg.M1000,
					"terminating version success");
		} catch (Exception e) {
			logger.error(e.getMessage());
			return new CommonResult(ReturnCodeDefine.Code.C1200, e.getMessage(), null);
		}
	}

	@RequestMapping(value = "/app/service/start", method = RequestMethod.POST)
	@ResponseBody
	public CommonResult startService(@RequestBody DmsServiceDTO service) {
		try {
			if (null == service || null == service.getServiceId())
				throw new RuntimeException("Error : some parameters are null, check them");
			appManagerService.startService(service.getServiceId());
			;
			return new CommonResult(ReturnCodeDefine.Code.C1000, ReturnCodeDefine.Msg.M1000, null);
		} catch (Exception e) {
			logger.error(e.getMessage());
			return new CommonResult(ReturnCodeDefine.Code.C1200, e.getMessage(), null);
		}
	}

	@RequestMapping(value = "/app/service/rollback", method = RequestMethod.POST)
	@ResponseBody
	public CommonResult serviceRollback(@RequestBody DmsRollbackDTO rollback) {
		try {
			if (null == rollback || null == rollback.getServiceId() || null == rollback.getVersionId())
				throw new RuntimeException("Error : some parameters are null, check them");
			appManagerService.rollbackService(rollback.getServiceId(), rollback.getVersionId());
			return new CommonResult(ReturnCodeDefine.Code.C1000, ReturnCodeDefine.Msg.M1000, null);
		} catch (Exception e) {
			logger.error(e.getMessage());
			return new CommonResult(ReturnCodeDefine.Code.C1200, e.getMessage(), null);
		}
	}

	@RequestMapping(value = "/app/service/replace", method = RequestMethod.POST)
	@ResponseBody
	public CommonResult replaceService(@RequestBody DmsServiceDTO service) {
		try {
			if (null == service.getServiceId() || null == service.getYamlContent())
				throw new RuntimeException("Error : some parameters are null, check them");
			appManagerService.replaceService(service);
			return new CommonResult(ReturnCodeDefine.Code.C1000, ReturnCodeDefine.Msg.M1000,
					"terminating version success");
		} catch (Exception e) {
			logger.error(e.getMessage());
			return new CommonResult(ReturnCodeDefine.Code.C1200, e.getMessage(), null);
		}
	}

	@RequestMapping(value = "/app/service/configLvs", method = RequestMethod.POST)
	@ResponseBody
	public CommonResult configLvs(@RequestBody DmsServiceDTO service) {
		try {
			if (null == service.getServiceId() || null == service.getUrl())
				throw new RuntimeException("Error : parameter is null");
			appManagerService.configLvs(service.getServiceId(), service.getUrl(), service.getExternalPort());
			return new CommonResult(ReturnCodeDefine.Code.C1000, ReturnCodeDefine.Msg.M1000,
					"rolling-update task committed");
		} catch (Exception e) {
			logger.error(e.getMessage());
			return new CommonResult(ReturnCodeDefine.Code.C1200, e.getMessage(), null);
		}
	}

	@RequestMapping(value = "/app/service/configAutoScaler", method = RequestMethod.POST)
	@ResponseBody
	public CommonResult configAutoScaler(@RequestBody DmsServiceDTO service) {
		try {
			if (null == service || null == service.getServiceId() || null == service.getIsAutoscalable())
				throw new RuntimeException("Error : some parameter is null");
			if (1 == service.getIsAutoscalable().intValue())
				this.checkAutoscalePolicy(service);
			appManagerService.configAutoScaler(service);
			return new CommonResult(ReturnCodeDefine.Code.C1000, ReturnCodeDefine.Msg.M1000, null);
		} catch (Exception e) {
			logger.error(e.getMessage());
			return new CommonResult(ReturnCodeDefine.Code.C1200, e.getMessage(), null);
		}
	}


	@RequestMapping(value = "/app/list", method = RequestMethod.GET)
	@ResponseBody
	public CommonResult getAppList(@RequestParam(value = "appCode", required = false) String appCode,
			@RequestParam(value = "pageNum", required = false) Integer pageNum,
			@RequestParam(value = "pageSize", required = false) Integer pageSize) {
		try {
			if (null == pageNum)
				pageNum = new Integer(1);
			if (null == pageSize)
				pageSize = new Integer(12);
			PageInfo<DmsAppReturnDTO> pageInfo = appManagerServiceAux.getAppDTOList(appCode, pageNum, pageSize);
			return new CommonResult(ReturnCodeDefine.Code.C1000, ReturnCodeDefine.Msg.M1000, pageInfo);
		} catch (Exception e) {
			logger.error(e.getMessage());
			return new CommonResult(ReturnCodeDefine.Code.C1200, e.getMessage(), null);
		}
	}

	@RequestMapping(value = "/app/detail", method = RequestMethod.GET)
	@ResponseBody
	public CommonResult getAppDetail(@RequestParam(value = "appId") Long appId)
	{
		try {
			DmsAppReturnDTO app = appManagerServiceAux.getAppDTO(appId);
			return new CommonResult(ReturnCodeDefine.Code.C1000, ReturnCodeDefine.Msg.M1000, app);
		} catch (Exception e) {
			logger.error(e.getMessage());
			return new CommonResult(ReturnCodeDefine.Code.C1200, e.getMessage(), null);
		}
	}

	@RequestMapping(value = "/app/service/detail", method = RequestMethod.GET)
	@ResponseBody
	public CommonResult getServiceDetail(@RequestParam(value = "serviceId") Long serviceId) {
		try {
			if (null == serviceId)
				throw new RuntimeException("Error : parameter is null");
			DmsServiceReturnDTO serviceDTO = appManagerServiceAux.getService(serviceId);
			return new CommonResult(ReturnCodeDefine.Code.C1000, ReturnCodeDefine.Msg.M1000, serviceDTO);
		} catch (Exception e) {
			logger.error(e.getMessage());
			return new CommonResult(ReturnCodeDefine.Code.C1200, e.getMessage(), null);
		}
	}

	@RequestMapping(value = "/app/service/list", method = RequestMethod.GET)
	@ResponseBody
	public CommonResult getServiceList(@RequestParam(value = "appId") Long appId,
			@RequestParam(value = "pageNum", required = false) Integer pageNum,
			@RequestParam(value = "pageSize", required = false) Integer pageSize) {
		try {
			if (null == pageNum)
				pageNum = new Integer(1);
			if (null == pageSize)
				pageSize = new Integer(12);
			PageInfo<DmsServiceReturnDTO> pageInfo = appManagerServiceAux.getServices(appId, pageNum, pageSize);
			return new CommonResult(ReturnCodeDefine.Code.C1000, ReturnCodeDefine.Msg.M1000, pageInfo);
		} catch (Exception e) {
			logger.error(e.getMessage());
			return new CommonResult(ReturnCodeDefine.Code.C1200, e.getMessage(), null);
		}
	}

	@RequestMapping(value = "/app/service/version/list", method = RequestMethod.GET)
	@ResponseBody
	public CommonResult getVersionList(@RequestParam("serviceId") Long serviceId) {
		try {
			Object versions = appManagerServiceAux.getVersions(serviceId);
			return new CommonResult(ReturnCodeDefine.Code.C1000, ReturnCodeDefine.Msg.M1000, versions);
		} catch (Exception e) {
			logger.error(e.getMessage());
			return new CommonResult(ReturnCodeDefine.Code.C1200, e.getMessage(), null);
		}

	}

	@RequestMapping(value = "/appCodeValidation", method = RequestMethod.GET)
	@ResponseBody
	public CommonResult validateAppcode(@RequestParam("appCode") String appCode, @RequestParam("namespace") String namespace) {
		try {
			Map<String, Object> map = new HashMap<>();
			if (appManagerService.appCodeExist(WebUtils.getCtgUser().getSysUserId(), namespace, appCode)) {
				map.put("exist", 1);
				map.put("message", "Invalid appCode, appCode already exists");
			} else {
				map.put("exist", 0);
				map.put("message", "Valid appCode, appCode does not exist");
			}
			return new CommonResult(ReturnCodeDefine.Code.C1000, ReturnCodeDefine.Msg.M1000, map);
		} catch (Exception e) {
			logger.error(e.getMessage());
			return new CommonResult(ReturnCodeDefine.Code.C1200, e.getMessage(), null);
		}
	}

	@RequestMapping(value = "/serviceCodeValidation", method = RequestMethod.GET)
	@ResponseBody
	public CommonResult validateServiceCode(@RequestParam("appId") Long appId,
			@RequestParam("serviceCode") String serviceCode) {
		try {
			Map<String, Object> map = new HashMap<>();
			if (appManagerService.serviceCodeExist(appId, serviceCode)) {
				map.put("exist", 1);
				map.put("message", "Invalid serviceCode, serviceCode already exists");
			} else {
				map.put("exist", 0);
				map.put("message", "Valid serviceCode, serviceCode does not exist");
			}
			return new CommonResult(ReturnCodeDefine.Code.C1000, ReturnCodeDefine.Msg.M1000, map);
		} catch (Exception e) {
			logger.error(e.getMessage());
			return new CommonResult(ReturnCodeDefine.Code.C1200, e.getMessage(), null);
		}
	}

	@RequestMapping(value = "/configs", method = RequestMethod.GET)
	@ResponseBody
	public CommonResult defaultConfigs() {
		try {
			HashMap<String, String> configs = new HashMap<>();
			configs.put("deployment.externalPort",
					PropertiesUtils.getConfigValueCache("config.properties", "deployment.externalPort"));
			configs.put("log.hostPath", PropertiesUtils.getConfigValueCache("config.properties", "log.hostPath"));
			configs.put("cpu.request", PropertiesUtils.getConfigValueCache("config.properties", "cpu.request"));
			configs.put("memory.request", PropertiesUtils.getConfigValueCache("config.properties", "memory.request"));
			configs.put("cpu.limit", PropertiesUtils.getConfigValueCache("config.properties", "cpu.limit"));
			configs.put("memory.limit", PropertiesUtils.getConfigValueCache("config.properties", "memory.limit"));
			configs.put("memory.unit", PropertiesUtils.getConfigValueCache("config.properties", "memory.unit"));

			return new CommonResult(ReturnCodeDefine.Code.C1000, ReturnCodeDefine.Msg.M1000, configs);
		} catch (Exception e) {
			logger.error(e.getMessage());
			return new CommonResult(ReturnCodeDefine.Code.C1200, e.getMessage(), null);
		}
	}

	

	private void checkAutoscalePolicy(DmsServiceDTO autoscalePolicy)
	{
		if(null == autoscalePolicy)
			throw new RuntimeException("Error : some parameter is null");		
		
		if(null == autoscalePolicy.getElasticIndicator() || null == autoscalePolicy.getMaxPodNum() 
				|| null == autoscalePolicy.getMinPodNum())
			throw new RuntimeException("Error : some parameter is null");
		if(autoscalePolicy.getElasticIndicator().equals("001"))	// by timeRate
		{
			if(null == autoscalePolicy.getTimeRate() || null == autoscalePolicy.getElasticEndTime() || null == autoscalePolicy.getElasticStartTime())
				throw new RuntimeException("Error : parameter timeRate or elasticStartTime or elasticEndTime is null");
			autoscalePolicy.setElasticEndTime(TimeUtils.fomatTimeMillisToDateStr(new Long(autoscalePolicy.getElasticEndTime())));
			autoscalePolicy.setElasticStartTime(TimeUtils.fomatTimeMillisToDateStr(new Long(autoscalePolicy.getElasticStartTime())));
		}
		else if(null == autoscalePolicy.getMaxCpu())	// by cpu
			throw new RuntimeException("Error : parameter maxCpu is null");
	}
	
}
